package ru.spb.osll.myfit.server.handler;

import static org.junit.Assert.assertEquals;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintStream;
import java.util.List;

import org.easymock.EasyMock;
import org.easymock.EasyMockSupport;
import org.easymock.IAnswer;
import org.junit.Before;
import org.junit.Test;

import ru.spb.osll.myfit.common.Include;
import ru.spb.osll.myfit.common.Page;
import ru.spb.osll.myfit.common.PageElement;
import ru.spb.osll.myfit.common.PageElementType;
import ru.spb.osll.myfit.common.SetUp;
import ru.spb.osll.myfit.common.Table;
import ru.spb.osll.myfit.common.TearDown;
import ru.spb.osll.myfit.common.TextParsingTools;
import ru.spb.osll.myfit.server.Converter;
import ru.spb.osll.myfit.server.ImportsPrinter;
import ru.spb.osll.myfit.server.parser.PageParserNew;
import ru.spb.osll.myfit.server.parser.PageParserUtils;
import ru.spb.osll.myfit.server.parser.RecursiveIncludeException;
import ru.spb.osll.myfit.server.parser.TableCreater;
import ru.spb.osll.myfit.util.CollectionUtils;
import ru.spb.osll.myfit.util.StringOutputStream;

public class ContentHandlerTest extends EasyMockSupport {
	private ContentHandler m_handler;
	private PageParserNew m_parser;
	private PageLoader loader;
	private ImportsPrinter importsPrinter;

	@Before
	public void setUp() {
		m_parser = new PageParserNew(new Converter());
		loader = createMockBuilder(PageLoader.class).withConstructor("").addMockedMethod("loadPage", String.class).createMock();
		importsPrinter = createMock(ImportsPrinter.class);
		m_handler = new ContentHandler(importsPrinter, "", loader);
	}
	
	@Test
	public void testSavePage() throws IOException, RecursiveIncludeException {

		StringOutputStream buf = new StringOutputStream();
		PrintStream stream = new PrintStream(buf);
		List<PageElement> list = m_parser.parsePage(CollectionUtils
				.list("|set node regeneration submit delay|30 min|"));
		Page page = new Page();
		for (PageElement element : list) {
			page.insert(element);
		}
		
		importsPrinter.printImports(EasyMock.same(page), EasyMock.isA(PrintStream.class));
		EasyMock.expectLastCall().andAnswer(new IAnswer<Object>() {@Override
		public Object answer() throws Throwable {
			PrintStream stream = (PrintStream)EasyMock.getCurrentArguments()[1];
			stream.append("!path fixtures.jar" + TableCreater.TABLE_SEPARATOR
				+ "|Import|" + "\r\n" + "|ru.spb.osll.myfit.examples|" + "\r\n"
				+ "\r\n");
			return null;
		}
		});
		
		replayAll();
		m_handler.savePage(page, stream);
		verifyAll();

		String expected = "!path fixtures.jar" + TableCreater.TABLE_SEPARATOR
				+ "|Import|" + "\r\n" + "|ru.spb.osll.myfit.examples|" + "\r\n"
				+ "\r\n" + "|set node regeneration submit delay|30 min|"
				+ TableCreater.TABLE_SEPARATOR;

		assertEquals(expected, buf.toString());

	}

	@Test
	public void testLoadPageWithInclude() throws IOException {
		List<String> SimpleLoadList = CollectionUtils
				.list("!include TestInclude");
		List<String> SimpleInckudeList = CollectionUtils
				.list("|set node regeneration submit delay|30 min|");

		String name = "PageWithImport";
		String setUpName = File.separator + File.separator + "SetUp"
				+ File.separator + TextParsingTools.DATA_FILE_NAME;
		String tearownName = File.separator + File.separator + "TearDown"
				+ File.separator + TextParsingTools.DATA_FILE_NAME;
		EasyMock.expect(loader.loadPage(name)).andReturn(SimpleLoadList);
		EasyMock.expect(loader.loadPage(setUpName)).andThrow(
				new FileNotFoundException(""));
		EasyMock.expect(loader.loadPage(tearownName)).andThrow(
				new FileNotFoundException(""));

		String nameInclude = File.separator + "TestInclude" + File.separator
				+ TextParsingTools.DATA_FILE_NAME;
		EasyMock.expect(loader.loadPage(nameInclude)).andReturn(
				SimpleInckudeList);
		EasyMock.expect(loader.loadPage(setUpName)).andThrow(
				new FileNotFoundException(""));
		EasyMock.expect(loader.loadPage(tearownName)).andThrow(
				new FileNotFoundException(""));

		replayAll();
		Page page = m_handler.loadPage(name, name, null);
		// System.err.println(page.countPageElements());

		assertEquals(1, page.countPageElements());
		assertEquals(PageElementType.INCLUDE.getKey(), page.getElement(0)
				.getType().getKey());
		Include include = (Include) page.getElement(0);
		assertEquals("TestInclude", include.getPath());
		Page pageInclude = include.getPage();
		assertEquals(1, pageInclude.countPageElements());
		assertEquals(PageElementType.TABLE, pageInclude.getElement(0).getType());
		verifyAll();
	}

	@Test
	public void testLoadSimplePage() throws IOException {
		// String text =
		// "|set node regeneration submit delay|30 min|\n\n|with cubetools|\n|write|10|files of size|10KB|using|10|threads|\n\n";
		List<String> SimpleLoadList = CollectionUtils.list(
				"|set node regeneration submit delay|30 min|",
				TableCreater.LINE_SEPARATOR, "|with cubetools|",
				"|write|10|files of size|10KB|using|10|threads|");
		String name = "SimPlePage";
		String setUpName = File.separator + File.separator + "SetUp"
				+ File.separator + TextParsingTools.DATA_FILE_NAME;
		String tearownName = File.separator + File.separator + "TearDown"
				+ File.separator + TextParsingTools.DATA_FILE_NAME;
		EasyMock.expect(loader.loadPage(name)).andReturn(SimpleLoadList);
		EasyMock.expect(loader.loadPage(setUpName)).andThrow(
				new FileNotFoundException(""));
		EasyMock.expect(loader.loadPage(tearownName)).andThrow(
				new FileNotFoundException(""));
		EasyMock.replay(loader);
		Page page = m_handler.loadPage(name, name, null);
		assertEquals(2, page.countPageElements());
		assertEquals("|set node regeneration submit delay|30 min|"
				+ TableCreater.LINE_SEPARATOR, PageParserUtils
				.tableToString((Table) page.getElement(0)));
		assertEquals("|with cubetools|" + TableCreater.LINE_SEPARATOR
				+ "|write|10|files of size|10KB|using|10|threads|"
				+ TableCreater.LINE_SEPARATOR, PageParserUtils
				.tableToString((Table) page.getElement(1)));

		EasyMock.verify(loader);
	}

	@Test
	public void testLoadPageWithImports() throws IOException {
		List<String> SimpleLoadList = CollectionUtils.list("|Import|",
				"|ru.spb.osll.myfit.examples|", TableCreater.LINE_SEPARATOR,
				"|set node regeneration submit delay|30 min|");
		String name = "PageWithImport";
		String setUpName = File.separator + File.separator + "SetUp"
				+ File.separator + TextParsingTools.DATA_FILE_NAME;
		String tearownName = File.separator + File.separator + "TearDown"
				+ File.separator + TextParsingTools.DATA_FILE_NAME;
		EasyMock.expect(loader.loadPage(name)).andReturn(SimpleLoadList);
		EasyMock.expect(loader.loadPage(setUpName)).andThrow(
				new FileNotFoundException(""));
		EasyMock.expect(loader.loadPage(tearownName)).andThrow(
				new FileNotFoundException(""));
		EasyMock.replay(loader);
		Page page = m_handler.loadPage(name, name, null);
		// System.err.println(page.countPageElements());

		assertEquals(1, page.countPageElements());
		assertEquals("|set node regeneration submit delay|30 min|"
				+ TableCreater.LINE_SEPARATOR, PageParserUtils
				.tableToString((Table) page.getElement(0)));

		EasyMock.verify(loader);
	}

	@Test
	public void testLoadPageWithSetUp() throws IOException {
		// String text =
		// "|set node regeneration submit delay|30 min|\n\n|with cubetools|\n|write|10|files of size|10KB|using|10|threads|\n\n";
		List<String> SimpleLoadList = CollectionUtils.list(
				"|set node regeneration submit delay|30 min|",
				TableCreater.LINE_SEPARATOR, "|with cubetools|",
				"|write|10|files of size|10KB|using|10|threads|",
				TableCreater.LINE_SEPARATOR);
		String name = "SimPlePage";

		List<String> SimpleSetUp = CollectionUtils.list("|Import|",
				"|ru.spb.osll.myfit.examples|", TableCreater.LINE_SEPARATOR,
				"|with cubetools|",
				"|write|1000000|files of size|10KB|using|80|threads|",
				TableCreater.LINE_SEPARATOR);

		String setUpName = File.separator + File.separator + "SetUp"
				+ File.separator + TextParsingTools.DATA_FILE_NAME;
		String tearownName = File.separator + File.separator + "TearDown"
				+ File.separator + TextParsingTools.DATA_FILE_NAME;
		EasyMock.expect(loader.loadPage(name)).andReturn(SimpleLoadList);
		EasyMock.expect(loader.loadPage(setUpName)).andReturn(SimpleSetUp);
		EasyMock.expect(loader.loadPage(tearownName)).andThrow(
				new FileNotFoundException(""));
		EasyMock.replay(loader);
		Page page = m_handler.loadPage(name, name, null);
		// System.err.println(page.countPageElements());

		assertEquals(3, page.countPageElements());
		assertEquals(PageElementType.SET_UP, page.getElement(0).getType());
		SetUp setUpinclude = (SetUp) page.getElement(0);
		Page pageSetUp = setUpinclude.getPage();
		assertEquals(1, pageSetUp.countPageElements());
		assertEquals(PageElementType.TABLE, page.getElement(1).getType());
		assertEquals("|set node regeneration submit delay|30 min|"
				+ TableCreater.LINE_SEPARATOR, PageParserUtils
				.tableToString((Table) page.getElement(1)));

		assertEquals(PageElementType.TABLE, page.getElement(2).getType());

		assertEquals("|with cubetools|" + TableCreater.LINE_SEPARATOR
				+ "|write|10|files of size|10KB|using|10|threads|"
				+ TableCreater.LINE_SEPARATOR, PageParserUtils
				.tableToString((Table) page.getElement(2)));

		EasyMock.verify(loader);
	}

	@Test
	public void testLoadPageWithTearDown() throws IOException {
		List<String> SimpleLoadList = CollectionUtils.list(
				"|set node regeneration submit delay|30 min|",
				TableCreater.LINE_SEPARATOR, "|with cubetools|",
				"|write|10|files of size|10KB|using|10|threads|",
				TableCreater.LINE_SEPARATOR);
		String name = "SimPlePage";

		List<String> SimpleTearnDown = CollectionUtils.list("|Import|",
				"|ru.spb.osll.myfit.examples|", TableCreater.LINE_SEPARATOR,
				"|with cubetools|",
				"|write|1000000|files of size|10KB|using|80|threads|",
				TableCreater.LINE_SEPARATOR);

		String setUpName = File.separator + File.separator + "SetUp"
				+ File.separator + TextParsingTools.DATA_FILE_NAME;
		String tearownName = File.separator + File.separator + "TearDown"
				+ File.separator + TextParsingTools.DATA_FILE_NAME;
		EasyMock.expect(loader.loadPage(name)).andReturn(SimpleLoadList);
		EasyMock.expect(loader.loadPage(setUpName)).andThrow(
				new FileNotFoundException(""));
		EasyMock.expect(loader.loadPage(tearownName))
				.andReturn(SimpleTearnDown);
		EasyMock.replay(loader);
		Page page = m_handler.loadPage(name, name, null);
		// System.err.println(page.countPageElements());

		assertEquals(3, page.countPageElements());
		assertEquals(PageElementType.TABLE, page.getElement(0).getType());
		assertEquals("|set node regeneration submit delay|30 min|"
				+ TableCreater.LINE_SEPARATOR, PageParserUtils
				.tableToString((Table) page.getElement(0)));

		assertEquals(PageElementType.TABLE, page.getElement(1).getType());

		assertEquals("|with cubetools|" + TableCreater.LINE_SEPARATOR
				+ "|write|10|files of size|10KB|using|10|threads|"
				+ TableCreater.LINE_SEPARATOR, PageParserUtils
				.tableToString((Table) page.getElement(1)));
		assertEquals(PageElementType.TEAR_DOWN, page.getElement(2).getType());
		TearDown setUpinclude = (TearDown) page.getElement(2);
		Page pageSetUp = setUpinclude.getPage();
		assertEquals(1, pageSetUp.countPageElements());
		EasyMock.verify(loader);
	}

	@Test
	public void testLoadRecursiveInclude() throws IOException {
		List<String> pageList1 = CollectionUtils.list(
				"|set node regeneration submit delay|30 min|",
				TableCreater.LINE_SEPARATOR, "|with cubetools|",
				"|write|10|files of size|10KB|using|10|threads|",
				TableCreater.LINE_SEPARATOR, "!include TestPage2");
		List<String> pageList2 = CollectionUtils.list("!include TestPage1");
		String pageName1 = "TestPage1";

		String pageName2 = File.separator + "TestPage2" + File.separator
				+ TextParsingTools.DATA_FILE_NAME;
		
		String setUpName = File.separator + File.separator + "SetUp"
				+ File.separator + TextParsingTools.DATA_FILE_NAME;
		String tearownName = File.separator + File.separator + "TearDown"
				+ File.separator + TextParsingTools.DATA_FILE_NAME;
		EasyMock.expect(loader.loadPage(pageName1)).andReturn(pageList1);
		EasyMock.expect(loader.loadPage(setUpName)).andThrow(
				new FileNotFoundException(""));
		EasyMock.expect(loader.loadPage(tearownName)).andThrow(
				new FileNotFoundException(""));
		EasyMock.expect(loader.loadPage(pageName2)).andReturn(pageList2);
		EasyMock.replay(loader);
		Page page = m_handler.loadPage(pageName1, pageName1, null);
		// System.err.println(page.countPageElements());

		assertEquals(3, page.countPageElements());
		assertEquals("|set node regeneration submit delay|30 min|"
				+ TableCreater.LINE_SEPARATOR, PageParserUtils
				.tableToString((Table) page.getElement(0)));
		assertEquals("|with cubetools|" + TableCreater.LINE_SEPARATOR
				+ "|write|10|files of size|10KB|using|10|threads|"
				+ TableCreater.LINE_SEPARATOR, PageParserUtils
				.tableToString((Table) page.getElement(1)));
		assertEquals(PageElementType.INCLUDE_ERROR, page.getElement(2)
				.getType());
		EasyMock.verify(loader);
	}

	@Test
	public void testLoadNotExistingInclude() throws IOException {
		List<String> SimpleLoadList = CollectionUtils.list(
				"|set node regeneration submit delay|30 min|",
				TableCreater.LINE_SEPARATOR, "|with cubetools|",
				"|write|10|files of size|10KB|using|10|threads|",
				TableCreater.LINE_SEPARATOR, "!include .NotExistingInclude");
		String name = "SimPlePage";
		String nameInclude = File.separator + File.separator
				+ "NotExistingInclude" + File.separator
				+ TextParsingTools.DATA_FILE_NAME;
		String setUpName = File.separator + File.separator + "SetUp"
				+ File.separator + TextParsingTools.DATA_FILE_NAME;
		String tearownName = File.separator + File.separator + "TearDown"
				+ File.separator + TextParsingTools.DATA_FILE_NAME;
		EasyMock.expect(loader.loadPage(name)).andReturn(SimpleLoadList);
		EasyMock.expect(loader.loadPage(setUpName)).andThrow(
				new FileNotFoundException(""));
		EasyMock.expect(loader.loadPage(tearownName)).andThrow(
				new FileNotFoundException(""));
		EasyMock.expect(loader.loadPage(nameInclude)).andThrow(
				new FileNotFoundException(""));
		EasyMock.replay(loader);
		Page page = m_handler.loadPage(name, name, null);
		// System.err.println(page.countPageElements());

		assertEquals(3, page.countPageElements());
		assertEquals("|set node regeneration submit delay|30 min|"
				+ TableCreater.LINE_SEPARATOR, PageParserUtils
				.tableToString((Table) page.getElement(0)));
		assertEquals("|with cubetools|" + TableCreater.LINE_SEPARATOR
				+ "|write|10|files of size|10KB|using|10|threads|"
				+ TableCreater.LINE_SEPARATOR, PageParserUtils
				.tableToString((Table) page.getElement(1)));
		assertEquals(PageElementType.INCLUDE_ERROR, page.getElement(2)
				.getType());
		EasyMock.verify(loader);
	}
}
